home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 24 / AACD 24.iso / AACD / Online / smbfs / source / sock.c < prev    next >
C/C++ Source or Header  |  2001-02-03  |  11KB  |  519 lines

  1. /*
  2.  * $Id: sock.c,v 1.13 2001/02/03 15:17:40 olsen Exp $
  3.  *
  4.  * :ts=8
  5.  *
  6.  * sock.c
  7.  *
  8.  * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
  9.  * Modified by Christian Starkjohann <cs@hal.kph.tuwien.ac.at>
  10.  * Modified for use with AmigaOS by Olaf Barthel <olsen@sourcery.han.de>
  11.  */
  12.  
  13. #include "system_headers.h"
  14. #include "assert.h"
  15.  
  16. /*****************************************************************************/
  17.  
  18. extern VOID FreeVecPooled(APTR address);
  19. extern APTR AllocVecPooled(ULONG size);
  20.  
  21. #define malloc(s) AllocVecPooled(s)
  22. #define free(m) FreeVecPooled(m)
  23.  
  24. /*****************************************************************************/
  25.  
  26. extern VOID SPrintf(STRPTR buffer, STRPTR formatString,...);
  27.  
  28. /*****************************************************************************/
  29.  
  30. #include <smb/smb_fs.h>
  31. #include <smb/smb.h>
  32. #include <smb/smbno.h>
  33.  
  34. /*****************************************************************************/
  35.  
  36. extern struct Library * SocketBase;
  37.  
  38. /*****************************************************************************/
  39.  
  40. extern void smb_invalidate_all_inodes (struct smb_server *server);
  41.  
  42. /*****************************************************************************/
  43.  
  44. /*
  45.  * smb_receive_raw
  46.  * fs points to the correct segment, sock != NULL, target != NULL
  47.  * The smb header is only stored if want_header != 0.
  48.  */
  49. static int
  50. smb_receive_raw (int sock_fd, unsigned char *target, int max_raw_length, int want_header)
  51. {
  52.   int len, result;
  53.   int already_read;
  54.   unsigned char peek_buf[4];
  55.  
  56.  re_recv:
  57.  
  58.   result = recvfrom (sock_fd, (void *) peek_buf, 4, 0, NULL, NULL);
  59.   if (result < 0)
  60.   {
  61.     LOG (("smb_receive_raw: recv error = %ld\n", errno));
  62.     result = (-errno);
  63.     goto out;
  64.   }
  65.  
  66.   if (result < 4)
  67.   {
  68.     LOG (("smb_receive_raw: got less than 4 bytes\n"));
  69.     result = -EIO;
  70.     goto out;
  71.   }
  72.  
  73.   switch (peek_buf[0])
  74.   {
  75.   case 0x00:
  76.   case 0x82:
  77.     break;
  78.   case 0x85:
  79.     LOG (("smb_receive_raw: Got SESSION KEEP ALIVE\n"));
  80.     goto re_recv;
  81.   default:
  82.     LOG (("smb_receive_raw: Invalid packet 0x%02lx\n", peek_buf[0]));
  83.     result = -EIO;
  84.     goto out;
  85.   }
  86.  
  87.   /* The length in the RFC NB header is the raw data length */
  88.   len = smb_len (peek_buf);
  89.   if (len > max_raw_length)
  90.   {
  91.     LOG (("smb_receive_raw: Received length (%ld) > max_xmit (%ld)!\n", len, max_raw_length));
  92.     result = -EIO;
  93.     goto out;
  94.   }
  95.  
  96.   if (want_header != 0)
  97.   {
  98.     memcpy (target, peek_buf, 4);
  99.     target += 4;
  100.   }
  101.  
  102.   already_read = 0;
  103.  
  104.   while (already_read < len)
  105.   {
  106.     result = recvfrom (sock_fd, (void *) (target + already_read), len - already_read, 0, NULL, NULL);
  107.     if (result < 0)
  108.     {
  109.       LOG (("smb_receive_raw: recvfrom error = %ld\n", errno));
  110.       result = (-errno);
  111.       goto out;
  112.     }
  113.  
  114.     already_read += result;
  115.   }
  116.  
  117.   result = already_read;
  118.  
  119.  out:
  120.  
  121.   return result;
  122. }
  123.  
  124. /*
  125.  * smb_receive
  126.  * fs points to the correct segment, server != NULL, sock!=NULL
  127.  */
  128. static int
  129. smb_receive (struct smb_server *server, int sock_fd)
  130. {
  131.   byte * packet = server->packet;
  132.   int result;
  133.  
  134.   result = smb_receive_raw (sock_fd, packet,
  135.                             server->max_recv - 4,  /* max_xmit in server includes NB header */
  136.                             1); /* We want the header */
  137.   if (result < 0)
  138.   {
  139.     LOG (("smb_receive: receive error: %ld\n", result));
  140.     goto out;
  141.   }
  142.  
  143.   server->rcls = *((unsigned char *) (packet + 9));
  144.   server->err = WVAL (packet, 11);
  145.  
  146.   if (server->rcls != 0)
  147.     LOG (("smb_receive: rcls=%ld, err=%ld\n", server->rcls, server->err));
  148.  
  149.  out:
  150.  
  151.   return result;
  152. }
  153.  
  154. /*
  155.  * smb_receive's preconditions also apply here.
  156.  */
  157. static int
  158. smb_receive_trans2 (struct smb_server *server, int sock_fd, int *data_len, int *param_len, char **data, char **param)
  159. {
  160.   unsigned char *inbuf = server->packet;
  161.   int total_data;
  162.   int total_param;
  163.   int result;
  164.  
  165.   LOG (("smb_receive_trans2: enter\n"));
  166.  
  167.   (*data_len) = (*param_len) = 0;
  168.   (*param) = (*data) = NULL;
  169.  
  170.   result = smb_receive (server, sock_fd);
  171.   if (result < 0)
  172.     goto fail;
  173.  
  174.   if (server->rcls != 0)
  175.     goto fail;
  176.  
  177.   /* parse out the lengths */
  178.   total_data = WVAL (inbuf, smb_tdrcnt);
  179.   total_param = WVAL (inbuf, smb_tprcnt);
  180.  
  181.   if ((total_data > server->max_xmit) || (total_param > server->max_xmit))
  182.   {
  183.     LOG (("smb_receive_trans2: data/param too long\n"));
  184.  
  185.     result = -EIO;
  186.     goto fail;
  187.   }
  188.  
  189.   /* allocate it */
  190.   (*data) = malloc (total_data);
  191.   if ((*data) == NULL)
  192.   {
  193.     LOG (("smb_receive_trans2: could not alloc data area\n"));
  194.  
  195.     result = -ENOMEM;
  196.     goto fail;
  197.   }
  198.  
  199.   (*param) = malloc(total_param);
  200.   if ((*param) == NULL)
  201.   {
  202.     LOG (("smb_receive_trans2: could not alloc param area\n"));
  203.  
  204.     result = -ENOMEM;
  205.     goto fail;
  206.   }
  207.  
  208.   LOG (("smb_rec_trans2: total_data/param: %ld/%ld\n", total_data, total_param));
  209.  
  210.   while (1)
  211.   {
  212.     if (WVAL (inbuf, smb_prdisp) + WVAL (inbuf, smb_prcnt) > total_param)
  213.     {
  214.       LOG (("smb_receive_trans2: invalid parameters\n"));
  215.       result = -EIO;
  216.       goto fail;
  217.     }
  218.  
  219.     memcpy (*param + WVAL (inbuf, smb_prdisp), smb_base (inbuf) + WVAL (inbuf, smb_proff), WVAL (inbuf, smb_prcnt));
  220.     (*param_len) += WVAL (inbuf, smb_prcnt);
  221.  
  222.     if (WVAL (inbuf, smb_drdisp) + WVAL (inbuf, smb_drcnt) > total_data)
  223.     {
  224.       LOG (("smb_receive_trans2: invalid data block\n"));
  225.       result = -EIO;
  226.       goto fail;
  227.     }
  228.  
  229.     memcpy ((*data) + WVAL (inbuf, smb_drdisp), smb_base (inbuf) + WVAL (inbuf, smb_droff), WVAL (inbuf, smb_drcnt));
  230.     (*data_len) += WVAL (inbuf, smb_drcnt);
  231.  
  232.     LOG (("smb_rec_trans2: drcnt/prcnt: %ld/%ld\n", WVAL (inbuf, smb_drcnt), WVAL (inbuf, smb_prcnt)));
  233.  
  234.     /* parse out the total lengths again - they can shrink! */
  235.     if ((WVAL (inbuf, smb_tdrcnt) > total_data) || (WVAL (inbuf, smb_tprcnt) > total_param))
  236.     {
  237.       LOG (("smb_receive_trans2: data/params grew!\n"));
  238.       result = -EIO;
  239.       goto fail;
  240.     }
  241.  
  242.     total_data = WVAL (inbuf, smb_tdrcnt);
  243.     total_param = WVAL (inbuf, smb_tprcnt);
  244.     if (total_data <= (*data_len) && total_param <= (*param_len))
  245.       break;
  246.  
  247.     result = smb_receive (server, sock_fd);
  248.     if (result < 0)
  249.       goto fail;
  250.  
  251.     if (server->rcls != 0)
  252.     {
  253.       result = -EIO;
  254.       goto fail;
  255.     }
  256.   }
  257.  
  258.   LOG (("smb_receive_trans2: normal exit\n"));
  259.   return 0;
  260.  
  261.  fail:
  262.  
  263.   LOG (("smb_receive_trans2: failed exit\n"));
  264.  
  265.   if((*param) != NULL)
  266.     free (*param);
  267.  
  268.   if((*data) != NULL)
  269.     free (*data);
  270.  
  271.   (*param) = (*data) = NULL;
  272.  
  273.   return result;
  274. }
  275.  
  276. int
  277. smb_release (struct smb_server *server)
  278. {
  279.   int result;
  280.  
  281.   if (server->mount_data.fd >= 0)
  282.     CloseSocket (server->mount_data.fd);
  283.  
  284.   server->mount_data.fd = socket (AF_INET, SOCK_STREAM, 0);
  285.   if (server->mount_data.fd < 0)
  286.   {
  287.     result = (-errno);
  288.     goto out;
  289.   }
  290.  
  291.   result = 0;
  292.  
  293.  out:
  294.  
  295.   return result;
  296. }
  297.  
  298. int
  299. smb_connect (struct smb_server *server)
  300. {
  301.   int sock_fd = server->mount_data.fd;
  302.   int result;
  303.  
  304.   if (sock_fd < 0)
  305.   {
  306.     result = (-EBADF);
  307.     goto out;
  308.   }
  309.  
  310.   result = connect (sock_fd, (struct sockaddr *)&server->mount_data.addr, sizeof(struct sockaddr_in));
  311.   if(result < 0)
  312.     result = (-errno);
  313.  
  314.  out:
  315.  
  316.   return(result);
  317. }
  318.  
  319. /*****************************************************************************
  320.  *
  321.  *  This routine was once taken from nfs, which is for udp. Here TCP does
  322.  *  most of the ugly stuff for us (thanks, Alan!)
  323.  *
  324.  ****************************************************************************/
  325. int
  326. smb_request (struct smb_server *server)
  327. {
  328.   int len, result;
  329.   int sock_fd = server->mount_data.fd;
  330.   unsigned char *buffer = server->packet;
  331.  
  332.   if ((sock_fd < 0) || (buffer == NULL))
  333.   {
  334.     LOG (("smb_request: Bad server!\n"));
  335.     result = -EBADF;
  336.     goto out;
  337.   }
  338.  
  339.   if (server->state != CONN_VALID)
  340.   {
  341.     result = -EIO;
  342.     goto out;
  343.   }
  344.  
  345.   len = smb_len (buffer) + 4;
  346.   LOG (("smb_request: len = %ld cmd = 0x%lx\n", len, buffer[8]));
  347.  
  348.   result = send (sock_fd, (void *) buffer, len, 0);
  349.   if (result < 0)
  350.   {
  351.     LOG (("smb_request: send error = %ld\n", errno));
  352.  
  353.     result = (-errno);
  354.   }
  355.   else
  356.   {
  357.     result = smb_receive (server, sock_fd);
  358.   }
  359.  
  360.  out:
  361.  
  362.   if (result < 0)
  363.   {
  364.     server->state = CONN_INVALID;
  365.     smb_invalidate_all_inodes (server);
  366.   }
  367.  
  368.   LOG (("smb_request: result = %ld\n", result));
  369.  
  370.   return (result);
  371. }
  372.  
  373. /*
  374.  * This is not really a trans2 request, we assume that you only have
  375.  * one packet to send.
  376.  */
  377. int
  378. smb_trans2_request (struct smb_server *server, int *data_len, int *param_len, char **data, char **param)
  379. {
  380.   int len, result;
  381.   int sock_fd = server->mount_data.fd;
  382.   unsigned char *buffer = server->packet;
  383.  
  384.   if (server->state != CONN_VALID)
  385.   {
  386.     result = -EIO;
  387.     goto out;
  388.   }
  389.  
  390.   len = smb_len (buffer) + 4;
  391.  
  392.   LOG (("smb_request: len = %ld cmd = 0x%02lx\n", len, buffer[8]));
  393.  
  394.   result = send (sock_fd, (void *) buffer, len, 0);
  395.   if (result < 0)
  396.   {
  397.     LOG (("smb_trans2_request: send error = %ld\n", errno));
  398.  
  399.     result = (-errno);
  400.   }
  401.   else
  402.   {
  403.     result = smb_receive_trans2 (server, sock_fd, data_len, param_len, data, param);
  404.   }
  405.  
  406.  out:
  407.  
  408.   if (result < 0)
  409.   {
  410.     server->state = CONN_INVALID;
  411.     smb_invalidate_all_inodes (server);
  412.   }
  413.  
  414.   LOG (("smb_trans2_request: result = %ld\n", result));
  415.  
  416.   return result;
  417. }
  418.  
  419. /* target must be in user space */
  420. int
  421. smb_request_read_raw (struct smb_server *server, unsigned char *target, int max_len)
  422. {
  423.   int len, result;
  424.   int sock_fd = server->mount_data.fd;
  425.   unsigned char *buffer = server->packet;
  426.  
  427.   if (server->state != CONN_VALID)
  428.   {
  429.     result = -EIO;
  430.     goto out;
  431.   }
  432.  
  433.   len = smb_len (buffer) + 4;
  434.  
  435.   LOG (("smb_request_read_raw: len = %ld cmd = 0x%02lx\n", len, buffer[8]));
  436.   LOG (("smb_request_read_raw: target=%lx, max_len=%ld\n", (unsigned int) target, max_len));
  437.   LOG (("smb_request_read_raw: buffer=%lx, sock=%lx\n", (unsigned int) buffer, (unsigned int) sock_fd));
  438.  
  439.   result = send (sock_fd, (void *) buffer, len, 0);
  440.   LOG (("smb_request_read_raw: send returned %ld\n", result));
  441.   if (result < 0)
  442.   {
  443.     LOG (("smb_request_read_raw: send error = %ld\n", errno));
  444.  
  445.     result = (-errno);
  446.   }
  447.   else
  448.   {
  449.     result = smb_receive_raw (sock_fd, target, max_len, 0);
  450.   }
  451.  
  452.  out:
  453.  
  454.   if (result < 0)
  455.   {
  456.     server->state = CONN_INVALID;
  457.     smb_invalidate_all_inodes (server);
  458.   }
  459.  
  460.   LOG (("smb_request_read_raw: result = %ld\n", result));
  461.  
  462.   return result;
  463. }
  464.  
  465. /* Source must be in user space. smb_request_write_raw assumes that
  466.  * the request SMBwriteBraw has been completed successfully, so that
  467.  * we can send the raw data now.
  468.  */
  469. int
  470. smb_request_write_raw (struct smb_server *server, unsigned const char *source, int length)
  471. {
  472.   int result;
  473.   byte nb_header[4];
  474.   int sock_fd = server->mount_data.fd;
  475.  
  476.   if (server->state != CONN_VALID)
  477.   {
  478.     result = -EIO;
  479.     goto out;
  480.   }
  481.  
  482.   smb_encode_smb_length (nb_header, length);
  483.  
  484.   result = send (sock_fd, (void *) nb_header, 4, 0);
  485.   if (result == 4)
  486.   {
  487.     result = send (sock_fd, (void *) source, length, 0);
  488.     if(result < 0)
  489.       result = (-errno);
  490.   }
  491.   else
  492.   {
  493.     if(result < 0)
  494.       result = (-errno);
  495.     else
  496.       result = -EIO;
  497.   }
  498.  
  499.   LOG (("smb_request_write_raw: send returned %ld\n", result));
  500.  
  501.   if (result == length)
  502.     result = smb_receive (server, sock_fd);
  503.  
  504.  out:
  505.  
  506.   if (result < 0)
  507.   {
  508.     server->state = CONN_INVALID;
  509.     smb_invalidate_all_inodes (server);
  510.   }
  511.  
  512.   if (result > 0)
  513.     result = length;
  514.  
  515.   LOG (("smb_request_write_raw: result = %ld\n", result));
  516.  
  517.   return result;
  518. }
  519.